package com.jinjie.shiro;


import com.jinjie.config.shiro.ShiroRealm;
import com.jinjie.config.shiro.filter.CustomShiroFilterFactoryBean;
import com.jinjie.reids.BaseRedisManager;
import com.jinjie.reids.RedisConfig;
import com.jinjie.reids.RedisProperties;
import com.jinjie.shiro.jwt.JwtFilter;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.*;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;


import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.*;

@Slf4j
@Configuration
public class ShiroConfig {

    @Value("redis.model")
    private String redisModel;
    @Resource
    private RedisProperties redisProperties;
    @Resource
    private RedisConfig redisConfig;
    @Resource
    private BaseRedisManager redisManager;

    /**
     * Filter Chain定义说明
     * <p>
     * 1、一个URL可以配置多个Filter，使用逗号分隔
     * 2、当设置多个过滤器时，全部验证通过，才视为通过
     * 3、部分过滤器可指定参数，如perms，roles
     */
    @Bean("shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        CustomShiroFilterFactoryBean shiroFilterFactoryBean = new CustomShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

        //过滤 默认路径
//        if(oConvertUtils.isNotEmpty(excludeUrls)){
//            String[] permissionUrl = excludeUrls.split(",");
//            for(String url : permissionUrl){
//                filterChainDefinitionMap.put(url,"anon");
//            }
//        }
        // 配置不会被拦截的链接 顺序判断

//        filterChainDefinitionMap.put("/sys/randomImage/**", "anon"); //登录验证码接口排除


        filterChainDefinitionMap.put("/test/**", "anon");
        //性能监控  TODO 存在安全漏洞泄露TOEKN（durid连接池也有）
        filterChainDefinitionMap.put("/actuator/**", "anon");

        // 添加自己的过滤器并且取名为jwt
        Map<String, Filter> filterMap = new HashMap<String, Filter>(1);
        //如果cloudServer为空 则说明是单体 需要加载跨域配置【微服务跨域切换】

        filterMap.put("jwt", new JwtFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        // <!-- 过滤链定义，从上向下顺序执行，一般将/**放在最为下边
        filterChainDefinitionMap.put("/**", "jwt");

        // 未授权界面返回JSON
        shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403");
        shiroFilterFactoryBean.setLoginUrl("/sys/common/403");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean("securityManager")
    public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);

        /*
         * 关闭shiro自带的session，详情见文档
         * http://shiro.apache.org/session-management.html#SessionManagement-
         * StatelessApplications%28Sessionless%29
         */
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        //自定义缓存实现,使用redis
        securityManager.setCacheManager(redisCacheManager());
        return securityManager;
    }

    /**
     * 下面的代码是添加注解支持
     *
     * @return
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        /**
         * 解决重复代理问题 github#994
         * 添加前缀判断 不匹配 任何Advisor
         */
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
        return defaultAdvisorAutoProxyCreator;
    }

    @Bean
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisCacheManager redisCacheManager() {
        log.info("===============(1)创建缓存管理器RedisCacheManager");
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager);

        //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
        redisCacheManager.setPrincipalIdFieldName("id");
        //用户权限信息缓存时间
        redisCacheManager.setExpire(200000);
        return redisCacheManager;
    }

/*    public IRedisManager getRedisManager() {
        IRedisManager manager;
        if (redisModel.equals(CommonConstant.REDIS_MODEL_STANDALONE)) {
            RedisManager redisManager = new RedisManager();
            redisManager.setHost(redisProperties.getHost() + ":" + redisProperties.getPort());
            redisManager.setDatabase(redisProperties.getDatabase());
            redisManager.setTimeout(0);
            if (!StringUtils.isEmpty(redisProperties.getPassword())) {
                redisManager.setPassword(redisProperties.getPassword());
            }
            redisManager.setJedisPoolConfig(redisConfig.jedisPoolConfig());

            manager = redisManager;
        } else if (redisModel.equals(CommonConstant.REDIS_MODEL_SENTINEL)) {
            RedisSentinelManager redisSentinelManager = new RedisSentinelManager();
            redisSentinelManager.setDatabase(redisProperties.getDatabase());
            redisSentinelManager.setMasterName(redisProperties.getSentinel().getMaster());
            redisSentinelManager.setTimeout(redisProperties.getTimeout());
            redisSentinelManager.setJedisPoolConfig(redisConfig.jedisPoolConfig());
            manager = redisSentinelManager;
        } else if (redisModel.equals(CommonConstant.REDIS_MODEL_CLUSTER)) {
            // redis集群支持，优先使用集群配置
            RedisClusterManager redisManager = new RedisClusterManager();
            manager = redisManager;
        } else {
            throw new BeanCreationException("未配置 redis.model ; 请检查配置文件！");
        }
        return manager;
    }*/


}
